/* 
*  Copyright (C) 2009-2010 WCG Project
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/



#define POST 1

new g_RestoreVelocity[33]
new Float:g_Velocity[33][3]
new Float:g_prevHealth[33]
const NoPainshock = ~(DMG_BURN|DMG_SHOCK|DMG_SONIC|DMG_ENERGYBEAM|DMG_DROWN|DMG_NERVEGAS|DMG_POISON|DMG_RADIATION|DMG_ACID)

//-----------------------------------------
// Register_Forwards()
//
//-----------------------------------------
public Register_Forwards()
{
	RegisterHam( Ham_Spawn, 				"player",	"HAM_PlayerSpawn_Post", POST )
	RegisterHam( Ham_TraceAttack,			"player",	"HAM_PlayerTraceAttack" )
	RegisterHam( Ham_Player_PreThink,		"player",	"HAM_PlayerPreThink" )
	RegisterHam( Ham_Player_PreThink,		"player",	"HAM_PlayerPreThink_Post", POST )
	RegisterHam( Ham_TakeDamage,			"player",	"HAM_PlayerTakeDamage" )
	RegisterHam( Ham_TakeDamage,			"player",	"HAM_PlayerTakeDamage_Post", POST )
	RegisterHam( Ham_Killed,				"player",	"HAM_PlayerKilled" )
	RegisterHam( Ham_Think,					"grenade",	"HAM_GrenadeThink")

	RegisterHam( Ham_Weapon_PrimaryAttack,	"weapon_knife",	"HAM_KnifePrimaryAttack")
	RegisterHam( Ham_Weapon_SecondaryAttack,"weapon_knife",	"HAM_KnifeSecondaryAttack")

	register_forward( FM_GetGameDescription,	"FWD_GetGameDescription")
	register_forward( FM_SetModel,				"FWD_SetModel_Post", POST )
	register_forward( FM_TraceLine,				"FWD_TraceLine_Post", POST )
	register_forward( FM_EmitSound,				"FWD_EmitSound" )
}



//-----------------------------------------
// FWD_GetGameDescription
//
//-----------------------------------------
public FWD_GetGameDescription()
{
	forward_return(FMV_STRING, GameInfo[GI_ModName])
	return FMRES_SUPERCEDE
}



//-----------------------------------------
// HAM_PlayerSpawn
//
//-----------------------------------------
public HAM_PlayerSpawn_Post( id )
{
	if( !is_user_alive(id) )
		return HAM_IGNORED

	// Store the player's team!
	PlayerInfo[id][PI_TeamID] = fm_get_user_team( id )

	if( !IsOnTeam(id) )
		return HAM_IGNORED

	// Clear buff data
	for( new i = 0 ; i < _:S_PLAYERBUFFINFO ; i++ )
		PlayerBuffInfo[id][S_PLAYERBUFFINFO:i] = 0

	// This is the first time the user has spawned this round
	if( !PlayerInfo[id][PI_HasSpawned] )
	{	
		WC3_PlayerSpawn_NewRound( id )
		PlayerInfo[id][PI_HasSpawned] = true
	}
	
	// Should be called at the end of each spawn
	WC3_PostSpawn( id )

	return HAM_IGNORED
}

static Float:g_SavedPos[33][3]

//-----------------------------------------
// HAM_PlayerPreThink
//
//-----------------------------------------
public HAM_PlayerPreThink( id )
{
	static Float:fVelocity, Float:vel[3]

	if( !is_user_connected(id) )
		return HAM_IGNORED
		
	if( !is_user_alive(id) )
	{
		// Check to see if spectated player has changed
		new iTarget = pev( id, pev_iuser2 )
		new Float:fTime = get_gametime()

		// Then we are looking at a new player or the last hud message has disappeared
		if ( PlayerInfo[id][PI_SpectatingID] != iTarget || g_fLastSpecDisplay[id] <= fTime )
		{
			// We have a valid target!!
			if ( is_user_alive( iTarget ) && iTarget != id )
			{
				WCG_ShowSpecInfo( id, iTarget )
				g_fLastSpecDisplay[id] = fTime + SPEC_HOLDTIME
			}
			PlayerInfo[id][PI_SpectatingID] = iTarget
		}
		return HAM_IGNORED
	}

	pev( id, pev_velocity, vel )

	fVelocity = vector_length( vel )

	PlayerInfo[id][PI_IsOnGround] = bool:(pev(id, pev_flags) & FL_ONGROUND)
	PlayerInfo[id][PI_Speed] = _:fVelocity

	if( PlayerInfo[id][PI_IsStunned] || PlayerInfo[id][PI_IsImmobilized] )
	{
		pev( id, pev_origin, g_SavedPos[id] )
		return HAM_IGNORED
	}

	if( !PlayerInfo[id][PI_IsOnGround] )
		g_RestoreVelocity[id] = 0

	else if( g_RestoreVelocity[id] > 0 )
	{
		g_Velocity[id][0] = vel[0]
		g_Velocity[id][1] = vel[1]
		g_Velocity[id][2] = vel[2]
	}

	if( fVelocity > MAX_CASTING_VELOCITY && PlayerInfo[id][PI_CastingSpell] )
	{
		// Set to true and let the interrupt task handle the rest
		PlayerInfo[id][PI_CastingInterrupted] = true
	}
	
	if( PlayerInfo[id][PI_IsOnGround] )
	{
		new TimeStepSound = pev(id, pev_flTimeStepSound)

		if( TimeStepSound != 999 )
		{
			// Amulet of the Cat
			if ( ITEM_Has( id, ITEM_AMULET ) > ITEM_NONE )
				set_pev( id, pev_flTimeStepSound, 999 )

			else if( PlayerInfo[id][PI_Stealthed] > 0 )
				set_pev( id, pev_flTimeStepSound, 999 )

			else if ( fVelocity < 180.0 )
				set_pev( id, pev_flTimeStepSound, 999 )

			else if( TimeStepSound > 500 )
				set_pev( id, pev_flTimeStepSound, 200 )
		}
	}
	return HAM_IGNORED
}



//-----------------------------------------
// HAM_PlayerPreThink_Post
//
//-----------------------------------------
public HAM_PlayerPreThink_Post( id )
{
	if( !is_user_alive(id) )
		return HAM_IGNORED

	if( PlayerInfo[id][PI_IsPolymorphed] )
		set_pev( id, pev_view_ofs, {0.0, 0.0, -10.0} )

	if( PlayerInfo[id][PI_IsStunned] || PlayerInfo[id][PI_IsImmobilized] )
	{
		if( g_SavedPos[id][0] || g_SavedPos[id][1] || g_SavedPos[id][2] )
		{
			set_pev( id, pev_origin, g_SavedPos[id] )
			fm_reset_user_velocity( id )
			xs_vec_set( g_SavedPos[id], 0.0, 0.0, 0.0 )
		}
		return HAM_IGNORED
	}

	else if( g_RestoreVelocity[id] == 0 )
		return HAM_IGNORED

	g_RestoreVelocity[id] = clamp( g_RestoreVelocity[id], -100, 100 )

	if( g_RestoreVelocity[id] < 0 )
	{
		g_RestoreVelocity[id]++
		return HAM_IGNORED
	}
	
	g_RestoreVelocity[id]--

	if( pev(id, pev_flags) & FL_ONTRAIN)
		return HAM_IGNORED
		
	static groundent
	groundent = pev( id, pev_groundentity )
	if( pev_valid(groundent) && (pev(groundent, pev_flags) & FL_CONVEYOR))
	{
		// Add pev_basevelocity to our stored velocity
		static Float:tempvel[3]
		pev(id, pev_basevelocity, tempvel)

		g_Velocity[id][0] += tempvel[0]
		g_Velocity[id][1] += tempvel[1]
		g_Velocity[id][2] += tempvel[2]
	}
	
	// Restore previous velocity
	set_pev(id, pev_velocity, g_Velocity[id])

	// Remove any jumping penaltys
//	set_pev(id, pev_fuser2, 0.0)

	return HAM_HANDLED
}


//-----------------------------------------
// HAM_PlayerTakeDamage
//
//-----------------------------------------
public HAM_PlayerTakeDamage( iVictim, inflictor, iAttacker, Float:fDamage, iDamageType )
{
	if( !is_user_alive( iVictim ) )
		return HAM_IGNORED

	pev( iVictim, pev_health, g_prevHealth[iVictim] )

	new iWeapon = UTIL_GetWeaponIndex( inflictor )

	// Store the weapon index. This is used if the player dies
	PlayerInfo[iVictim][PI_LastHitByWeaponIndex] = iWeapon

	if( iWeapon == CSW_C4 )
		return HAM_IGNORED

	if( iWeapon == CSW_CRITICAL_GRENADE )
	{
		new iSkillLevel = pev( inflictor, pev_iuser2 )
		fDamage = fDamage * p_grenade[iSkillLevel-1]
	}

	if( !is_user_connected( iAttacker ) )
		return HAM_IGNORED

	// Fix the damage type for knife, since counter-strike thinks it's a bullet for some unknown reason
	if( iWeapon == CSW_KNIFE )
		iDamageType = iDamageType & ~DMG_BULLET | DMG_SLASH

	// friendly fire off?
	if( !get_pcvar_num( CVAR_mp_friendlyfire ) )
	{
		if( PlayerInfo[iVictim][PI_TeamID] == PlayerInfo[iAttacker][PI_TeamID] && iAttacker != iVictim )
			return HAM_SUPERCEDE
	}

	// No speed punishment on certain damage types
	if( !(iDamageType & NoPainshock) && iDamageType )
		g_RestoreVelocity[iVictim] += 100
	else
		g_RestoreVelocity[iVictim] -= 100

	if( iDamageType & DMG_BULLET )
		fDamage *= 0.9

	if( iDamageType & (DMG_BULLET|DMG_SLASH) )
		fDamage = fDamage + fDamage / PlayerInfo[iAttacker][PI_AttackModifier]

	if( iDamageType & (DMG_BULLET|DMG_SLASH|DMG_HEGRENADE) )
		fDamage *= 1.0-((PlayerInfo[iVictim][PI_Level]/MAX_LEVELS)*0.10)

	if( PlayerInfo[iVictim][PI_IsPolymorphed] )
		fDamage *= 2.0

	new iDamage = floatround( fDamage )

	switch( PlayerInfo[iAttacker][PI_Class] )
	{
		case CLASS_ROGUE:			ROGUE_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_PALADIN:			PALADIN_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_SHAMAN:			SHAMAN_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_DRUID:			DRUID_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_WARLOCK:			WARLOCK_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_HUNTER:			HUNTER_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_PRIEST:			PRIEST_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
		case CLASS_MAGE:			MAGE_SkillsOffensive( iAttacker, iVictim, iWeapon, iDamage, iDamageType )
	}

	switch( PlayerInfo[iVictim][PI_Class] )
	{
		case CLASS_ROGUE:			ROGUE_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_PALADIN:			PALADIN_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
//		case CLASS_SHAMAN:			SHAMAN_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_DRUID:			DRUID_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_WARLOCK:			WARLOCK_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_HUNTER:			HUNTER_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_PRIEST:			PRIEST_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
		case CLASS_MAGE:			MAGE_SkillsDefensive( iAttacker, iVictim, iDamage, iWeapon, iDamageType )
	}

	// Item abilities
	ITEM_Offensive( iAttacker, iVictim, iWeapon, iDamage )

//	debug_print( "iDamage = %d", iDamage )

	SetHamParamFloat( 4, float(iDamage) )

	return HAM_HANDLED
}


//-----------------------------------------
// HAM_PlayerTakeDamage_Post
//
//-----------------------------------------
public HAM_PlayerTakeDamage_Post( iVictim, inflictor, iAttacker, Float:fDamage, iDamageType )
{
	if( !is_user_connected(iVictim) )
		return HAM_IGNORED

	PlayerInfo[iVictim][PI_Hitgroup] = HIT_GENERIC

	if( fDamage > 0.0 && PlayerInfo[iVictim][PI_Stealthed] > 0 )
		_RemoveStealth( iVictim )

	if( fDamage > 0.0 && PlayerInfo[iVictim][PI_IsPolymorphed] )
	{
		emit_sound( iVictim, CHAN_STATIC, g_szSounds[SOUND_KILLCHICKEN], VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
		_RemovePolyChicken( iVictim )
	}


	if( !is_user_connected( iAttacker ) )
		return HAM_IGNORED

	if( !get_pcvar_num( CVAR_mp_friendlyfire ) )
	{
		if( PlayerInfo[iVictim][PI_TeamID] == PlayerInfo[iAttacker][PI_TeamID] )
			return HAM_IGNORED
	}

	new Float:fHealth
	pev( iVictim, pev_health, fHealth )

	new Float:fActualDamage = g_prevHealth[iVictim] - fHealth

	if( fHealth < 0 )
		fActualDamage = fHealth + fActualDamage

	g_iDamageDealt[iAttacker][iVictim] += floatround( fActualDamage )

	if( is_user_alive(iAttacker) && PlayerInfo[iAttacker][PI_Class] == CLASS_PRIEST )
		PRIEST_VampiricEmbrace( iAttacker, fActualDamage, (ITEM_Has( iAttacker, ITEM_MASK ) > ITEM_NONE) )

//	debug_print( "fActualDamage = %0.2f, fDamage = %0.2f", fActualDamage, fDamage )

	return HAM_IGNORED
}


//-----------------------------------------
// HAM_PlayerTraceAttack
//
//-----------------------------------------
public HAM_PlayerTraceAttack( iVictim, iAttacker, Float:fDamage, Float:vAngle[3], hTrace, iDamageType )
{
	static iHitgroup

	if( !is_user_alive(iVictim) || !is_user_connected( iAttacker ) )
		return HAM_IGNORED

	iHitgroup = get_tr2( hTrace, TR_iHitgroup )

	// Store which hitgroup this trace hit on the victim
	PlayerInfo[iVictim][PI_Hitgroup] = iHitgroup

	if( iDamageType & DMG_BULLET )
	{
		if( PlayerInfo[iVictim][PI_IsPolymorphed] )
		{
			static Float:vHit[3], Float:vOrigin[3]
			
			get_tr2( hTrace, TR_vecEndPos, vHit )

			pev( iVictim, pev_origin, vOrigin )

			new Float:y = vHit[2] - vOrigin[2]

			if( y > -4.0 )
				return HAM_SUPERCEDE
			else
			{
				set_tr2( hTrace, TR_iHitgroup, float(HIT_GENERIC) )
				return HAM_HANDLED
			}
		}

		// Check evade through AGI
		new Float:fChance = float( (PlayerInfo[iVictim][PI_Level] + PlayerInfo[iVictim][PI_AGI] * 4) ) * 0.0006
		if( fChance > 0.0 && random_float( 0.0, 1.0 ) <= fChance )
		{
			SHARED_Glow( iVictim, COLOR_RGB( 0, 0, 100 ) )
			EFFECT_ScreenFade( iVictim, 0.25, 0.25, COLOR_RGBA(0, 0, 255, 100) )
//			WCG_StatusText( iVictim, TXT_SKILL, HUD_SKILL, "You have evaded a shot!" )
			return HAM_SUPERCEDE
		}

		if( PlayerInfo[iVictim][PI_Class] == CLASS_DRUID )
		{
			if( DRUID_Quickness( iVictim, iHitgroup ) )
				return HAM_SUPERCEDE
		}
		else if( PlayerInfo[iVictim][PI_Class] == CLASS_ROGUE )
		{
			if( ROGUE_Evasion( iVictim, iHitgroup ) )
				return HAM_SUPERCEDE
		}			

		// Check for Helm of Excellence
/*		else if( iHitgroup == HIT_HEAD && ITEM_Has( iVictim, ITEM_HELM ) > ITEM_NONE )
		{
			// Create a screen fade
			EFFECT_ScreenFade( iVictim, 0.25, 0.25, COLOR_RGBA(0,0,255,150) )

			// Lets remove a charge from the helm only if the attacker is on the opposite team
			if( PlayerInfo[iAttacker][PI_TeamID] != PlayerInfo[iVictim][PI_TeamID] )
				ITEM_RemoveCharge( iVictim, ITEM_HELM )

			return HAM_SUPERCEDE
		}
*/
		// Check if Divine Protection is active on the victim
		else if( PlayerBuffInfo[iVictim][BUFF_DivineProtection] || PlayerInfo[iVictim][PI_IsCheatDeathActive] )
		{
			set_tr2( hTrace, TR_iHitgroup, float(HIT_GENERIC) )					// All shield hits are HIT_GENERIC
			return HAM_HANDLED
		}
	}

	return HAM_IGNORED
}




//-----------------------------------------
// HAM_GrenadeThink
//
//-----------------------------------------
public HAM_GrenadeThink( ent )
{
	static Float:dmgtime

	if( !pev_valid(ent) )
		return HAM_IGNORED

	pev( ent, pev_dmgtime, dmgtime )
	
	// Check if it's time to go off
	if( dmgtime > get_gametime() || !pev( ent, pev_iuser3 ) )
		return HAM_IGNORED

	switch( pev(ent, pev_iuser1 ) )
	{
		case CSW_BEASTWITHIN_GRENADE:
		{
			set_pev( ent, pev_iuser1, CSW_HEGRENADE )

			new Float:fDamage
			new iSkillLevel = pev( ent, pev_iuser2 )
			pev( ent, pev_dmg, fDamage )

			set_pev( ent, pev_dmg, fDamage * (1.0 + (0.20 * iSkillLevel / 5) ) )
		}
		
		case CSW_CRITICAL_GRENADE:
		{
			new Float:fDamage
			new iSkillLevel = pev( ent, pev_iuser2 )
			pev( ent, pev_dmg, fDamage )

			// This will increase the radius as well as base damage of the grenade
			// Extra damage are then applied in the ham_takedamage forward
			set_pev( ent, pev_dmg, fDamage * (1.0 + (0.25 * iSkillLevel / 5) ) )
		}

		case CSW_FROSTNOVA_GRENADE:
			MAGE_FrostNova( ent )
	}

	set_pev( ent, pev_iuser3, false )
	return HAM_IGNORED
}



//-----------------------------------------
// HAM_PlayerKilled
//
//-----------------------------------------
public HAM_PlayerKilled( iVictim, iAttacker, ShouldGib )
{
	if( !is_user_connected(iVictim) )
		return HAM_IGNORED

	new iWeapon = PlayerInfo[iVictim][PI_LastHitByWeaponIndex]

	_RemovePolyChicken( iVictim )
	_RemoveFrostNova( iVictim ) 

	PlayerInfo[iVictim][PI_RespawnBy]				= 0			// Reset the "about to spawn" variable
	PlayerInfo[iVictim][PI_IsSearching]				= false		// No longer have any active searching spells
	PlayerInfo[iVictim][PI_DiedLastRound]			= true		// Yes the user died...

	if( PlayerInfo[iVictim][PI_SerpentCount] > 0 )
		PlayerInfo[iVictim][PI_KillAllWards]		= true

	PlayerInfo[iVictim][PI_IsBurning]				= false		// User should not be burning
	PlayerInfo[iVictim][PI_IsCheatDeathActive]		= false

	remove_task( TASK_SEARCHPING + iVictim )
	remove_task( TASK_ALIVE_EFFECT + iVictim )

	Create_BarTime( iVictim, 0, 0 )
	ClearSyncHud( iVictim, g_HUDSync_StatusText )

	// Player is no longer casting any spells
	PLAYER_RemoveSpellCasting( iVictim )

	// Remove icon because you don't have an ultimate when you're dead
	ULT_ClearIcons( iVictim )
	Ability_ClearIcons( iVictim )

	PlayerInfo[iVictim][PI_Nightvision]	= (cs_get_user_nvg( iVictim )) ? true : false		// Check for NightVision
	PlayerInfo[iVictim][PI_Shield]		= (cs_get_user_shield( iVictim )) ? true : false	// Check if a user had a shield on death
	PlayerInfo[iVictim][PI_Defuse]		= (cs_get_user_defuse( iVictim )) ? true : false	// See if the user has a defuse kit
	PlayerInfo[iVictim][PI_FlashCount]	= cs_get_user_bpammo( iVictim, CSW_FLASHBANG )		// Save the number of flash grenades the user has
	
	// Check to see if weapons were silenced or burst on death
	new iWeaponUSPEnt = fm_find_ent_by_owner( -1, "weapon_usp", iVictim )
	new iWeaponM4A1Ent = fm_find_ent_by_owner( -1, "weapon_m4a1", iVictim )
	new iWeaponGlock18Ent = fm_find_ent_by_owner( -1, "weapon_glock18", iVictim )
	new iWeaponFamasEnt = fm_find_ent_by_owner( -1, "weapon_famas", iVictim )
	
	if( pev_valid( iWeaponUSPEnt ) )
		PlayerInfo[iVictim][PI_USP_Silenced] = cs_get_weapon_silen( iWeaponUSPEnt ) ? true : false

	if( pev_valid( iWeaponM4A1Ent ) )
		PlayerInfo[iVictim][PI_M4A1_Silenced] = cs_get_weapon_silen( iWeaponM4A1Ent ) ? true : false

	if( pev_valid( iWeaponGlock18Ent ) )
		PlayerInfo[iVictim][PI_GlockBurst] = cs_get_weapon_burst( iWeaponGlock18Ent ) ? true : false

	if( pev_valid( iWeaponFamasEnt ) )
		PlayerInfo[iVictim][PI_FamasBurst] = cs_get_weapon_burst( iWeaponFamasEnt ) ? true : false

	// Award XP
	XP_onDeath( iVictim, iAttacker, iWeapon )

	// Does the user have a scroll?
	if ( ITEM_Has( iVictim, ITEM_SCROLL ) > ITEM_NONE )
		ITEM_Scroll( iVictim )

	// Should we respawn with soulstone?
	if( PlayerInfo[iVictim][PI_Class] == CLASS_WARLOCK && iAttacker != iVictim )
		WARLOCK_CheckSoulstone( iVictim )

	// Remove hex if the user is hexed
//	_HUNTER_RemoveHex( TASK_HEX + iVictim )

	ITEM_UserDied( iVictim )
	return HAM_IGNORED
}



//-----------------------------------------
// HAM_KnifePrimaryAttack
//
//-----------------------------------------
public HAM_KnifePrimaryAttack( ent )
{
	if( !pev_valid( ent ) )
		return HAM_IGNORED

	new id = pev( ent, pev_owner )

	if( !IsValidUser( id ) )
		return HAM_IGNORED

	PlayerInfo[id][PI_KnifeAttackType] = 1
	return HAM_IGNORED
}



//-----------------------------------------
// HAM_KnifeSecondaryAttack
//
//-----------------------------------------
public HAM_KnifeSecondaryAttack( ent )
{
	if( !pev_valid( ent ) )
		return HAM_IGNORED

	new id = pev( ent, pev_owner )

	if( !IsValidUser( id ) )
		return HAM_IGNORED

	PlayerInfo[id][PI_KnifeAttackType] = 2
	return HAM_IGNORED
}



//-----------------------------------------
// FWD_SetModel
//
//-----------------------------------------
public FWD_SetModel_Post( entity, const model[] )
{
	static id, Float:dmgtime, iSkillLevel

	if( !pev_valid( entity ) )
		return FMRES_IGNORED

	pev( entity, pev_dmgtime, dmgtime )
	
	if( dmgtime == 0.0 )
		return FMRES_IGNORED

	if( equal( model[7], "w_he", 4 ) )
	{
		id = pev( entity, pev_owner )

		if( !is_user_connected(id) )
			return FMRES_IGNORED

		set_pev( entity, pev_iuser1, CSW_HEGRENADE )
		
		// User has gloves!  Do we need to give them another grenade?
		if( is_user_alive(id) && ITEM_Has( id, ITEM_GLOVES ) > ITEM_NONE )
			ITEM_Glove_Begin( id )

		if( PlayerBuffInfo[id][BUFF_BeastWithin] == true )
		{
			iSkillLevel = SM_GetSkillLevel( id, ULTIMATE_BEASTWITHIN )
			if( iSkillLevel > 0 && PLAYER_EnhancedGrenadeAllowed( id ) )
			{
				set_pev( entity, pev_iuser1, CSW_BEASTWITHIN_GRENADE )
				set_pev( entity, pev_iuser2, iSkillLevel )
				set_pev( entity, pev_iuser3, true )

				set_pev( entity, pev_renderfx, kRenderFxGlowShell )
				set_pev( entity, pev_rendercolor, {255.0, 64.0, 0.0} )
				set_pev( entity, pev_rendermode, kRenderNormal )
				set_pev( entity, pev_renderamt, 32.0 )

				Create_TE_BEAMFOLLOW( entity, g_spr_smoke, 20, 8, 255, 64, 0, 196 )
			}
		}


		// Critical Grenade
		iSkillLevel = SM_GetSkillLevel( id, SKILL_CRITICALGRENADE )
		if( iSkillLevel > 0 && PLAYER_EnhancedGrenadeAllowed( id ) )
		{
			set_pev( entity, pev_classname, "critical grenade" )
			set_pev( entity, pev_iuser1, CSW_CRITICAL_GRENADE )
			set_pev( entity, pev_iuser2, iSkillLevel )
			set_pev( entity, pev_iuser3, true )

			set_pev( entity, pev_renderfx, kRenderFxGlowShell )
			set_pev( entity, pev_rendercolor, {255.0, 20.0, 0.0} )
			set_pev( entity, pev_rendermode, kRenderNormal )
			set_pev( entity, pev_renderamt, 32.0 )

			Create_TE_BEAMFOLLOW( entity, g_spr_smoke, 20, 2*iSkillLevel, 255, 32, 32, 196*iSkillLevel/5 )
			return FMRES_IGNORED
		}
		
		// Frost Nova Grenade
		iSkillLevel = SM_GetSkillLevel( id, SKILL_FROSTNOVA )
		if( iSkillLevel > 0 && PLAYER_EnhancedGrenadeAllowed( id ) )
		{
			set_pev( entity, pev_classname, "frostnova grenade" )
			set_pev( entity, pev_iuser1, CSW_FROSTNOVA_GRENADE )
			set_pev( entity, pev_iuser2, iSkillLevel )
			set_pev( entity, pev_iuser3, true )

			set_pev( entity, pev_renderfx, kRenderFxGlowShell )
			set_pev( entity, pev_rendercolor, {0.0, 128.0, 255.0} )
			set_pev( entity, pev_rendermode, kRenderNormal )
			set_pev( entity, pev_renderamt, 32.0 )

			Create_TE_BEAMFOLLOW( entity, g_spr_smoke, 20, 2*iSkillLevel, 64, 172, 255, 172*iSkillLevel/5 )
			return FMRES_IGNORED
		}
	}
	return FMRES_IGNORED
}



//-----------------------------------------
// FWD_TraceLinePost
//
//-----------------------------------------
public FWD_TraceLine_Post( const Float:v1[3], const Float:v2[3], noMonsters, id, trace )
{
	static iVictim

	if( !is_user_alive(id) || !IsOnTeam(id) )
		return FMRES_IGNORED

	// This is a check for spells that need to "search" for a target
	if( PlayerInfo[id][PI_IsSearching] && !GameInfo[GI_EndRound] && !GameInfo[GI_FreezeTime])
	{
		iVictim = get_tr2( trace, TR_pHit )

		if( !is_user_alive(iVictim) )
			return FMRES_IGNORED

		// Now lets make sure the person he's looking at meets the team conditions
		if( PlayerInfo[iVictim][PI_TeamID] == PlayerInfo[id][PI_SearchTeamID] || PlayerInfo[id][PI_SearchTeamID] == TEAM_UNASSIGNED )
		{
			static Float:vOrigin[3]
			get_tr2( trace, TR_vecEndPos, vOrigin )

			if( fm_is_visible( id, vOrigin ) )
			{
				PlayerInfo[id][PI_IsSearching] = false
			
				remove_task( TASK_SEARCHPING + id )
			
				ULT_Icon( id, ICON_SHOW )
			
				// Once we go past this point, the information in PI_Searchxxx may not be valid anymore
				new param[5]

				param[0] = id
				param[1] = iVictim
				param[2] = PlayerInfo[id][PI_SearchSkillID]
				param[3] = PlayerInfo[id][PI_SearchTeamID]
				param[4] = PlayerInfo[id][PI_SearchFlags]
			
				PLAYER_CastSpell( id, PlayerInfo[id][PI_SearchSkillID], CAST_NORMAL, PlayerInfo[id][PI_SearchTaskName], param, sizeof(param), PlayerInfo[id][PI_SearchFlags] )
			}
		}
	}
	return FMRES_IGNORED
}


// Emit Sound Forward
public FWD_EmitSound( entity, channel, const sample[], Float:volume, Float:attn, flags, pitch )
{
	if( sample[0] == 'w' && sample[8] == 'f' && sample[9] == 'l' )
	{
		if( !pev_valid( entity ) )
			return FMRES_IGNORED

		new Float:fOrigin[3]
		new iOrigin[3]

		pev( entity, pev_origin, fOrigin )

		iOrigin[0] = floatround( fOrigin[0] )
		iOrigin[1] = floatround( fOrigin[1] )
		iOrigin[2] = floatround( fOrigin[2] )

		Create_TE_DLIGHT( iOrigin, 50, 255, 255, 255, 8, 60 )
	}
	
	return FMRES_IGNORED
}
